/*
 * Copyright [2021] [liufeng]
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.f.security;

import com.f.cache.CacheTemplate;
import com.f.config.ApplicationProperties;
import com.f.log.RequestWrapper;
import com.f.utils.WebUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 登录授权过滤器
 *
 * @author liuf
 * @date 2021年12月3日
 */
@Slf4j
@RequiredArgsConstructor
public class SysAuthenticationFilter implements Filter {

    private final CacheTemplate cacheTemplate;
    private final ApplicationProperties applicationProperties;
    /**
     * 随机多少次
     */
    private static final short COUNT = 1 << 5;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String token = httpRequest.getHeader("token");
        if (token != null) {
            final Object object = cacheTemplate.syncObject().get(token);
            if (object != null) {
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(object, null, null);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                // 刷新token
                refreshToken(token);
            } else {
                WebUtils.responseToLogin(response);
                return;
            }
        }
        chain.doFilter(HttpMethod.GET.matches(httpRequest.getMethod()) ? request : new RequestWrapper(httpRequest), response);
    }

    /**
     * 刷新token
     *
     * @param token token
     */
    private void refreshToken(String token) {
        if (ThreadLocalRandom.current().nextInt(COUNT) == 1) {
            log.info("刷新token");
            cacheTemplate.reactiveObject().expire(token, applicationProperties.getAuth().getTokenExpire()).subscribe();
        }
    }
}